#!/usr/bin/env python
import socket
import select
import sys
import re
import getopt
import packet_set
import socket_thread
#import server_thread
import time
from xml.dom import minidom

def get_argv(argv):      
    global filename,remote,listen,port,times                    
    try:                                
        #opts, args = getopt.getopt(argv, "Hf:h:p:U:P:", ["help", "file=", "host=", "port=","user=","password="])
        opts, args = getopt.getopt(argv, "Hf:r:l:p:T:",["help","file=","remote=","listen=","port=","times="])
    except getopt.GetoptError:   
        print "syntax error!"       
        usage()                         
        sys.exit(2)                     
    for opt, arg in opts:                
        if opt in ("-H", "--help"):      
            usage()                     
            sys.exit()                  
        elif opt == '-d':                
            global _debug               
            _debug = 1                  
        elif opt in ("-f", "--file="): 
            filename = arg      
        elif opt in ("-r", "--remote"): 
            remote = arg      
        elif opt in ("-l", "--listen"): 
            listen = arg      
        elif opt in ("-p", "--port"): 
            port = arg      
        elif opt in ("-T", "--times"):
            times = arg
def usage():
    print "-f/--file=      specify file which includes sending content"
    print "-r/--remote=    specify which remote ip to access,means client mode"
    print "-l/--listen=    specify which ip to listen,means server mode"
    print "-p/--port=      specify which port to access"
    print "-d              enable debug"
    print "-h/--help       print out this help"
    print "-T/--times      specify how many times to get" 

def check_recv(action,data):
    #if receiving packet is correct. action_step should increase by 1. otherwise do not need change action_step
    #suppose packet checking always pass
    increase_action_step=1
    return increase_action_step

def handle_action(seq,thread,packet,action):
    #if send one packet, then action_step should increase by 1. otherwise do not need change action_step
    increase_action_step=0
    packet.seq=seq
    for key in action.attr :
        setattr(thread, key, action.attr[key])
        #print "key is ",key, "value is ",packet.h_teid
    if action.action=='send' :
        send_content=''
        print "in handle_action, action_type is ",action.type
        if action.type=='create_pdp_req' :
            send_content=packet.create_pdp_req()
            print "in handle_action. send one create_pdp_req"
        elif action.type=='pdp_echo_req' :
            send_content=packet.pdp_echo_req()
            print "in handle_action. send one pdp_echo_req"
            print "send_content is ", send_content
        send_content=send_content.rstrip('\r\n')
        thread.send(send_content)
        increase_action_step=1
    return increase_action_step
    
    
def parse_xml(filename):
    doc=minidom.parse(filename)
    actions={}
    i=0
    for level1 in doc.childNodes :
        #print level1.toxml()
        print "level1 tagName is ", level1.tagName
        value= level1.attributes["name"].value
        print "value is ", value
        if value=="gtp_client":
            for level2 in level1.childNodes :
                if level2.toxml().strip('\r\n') <> "" :
                    i+=1
                    actions[i]=packet_set.gtp_custom()
                    actions[i].action=level2.tagName.strip()
                    print "level2 tagName is ", level2.tagName
                    action=level2.tagName
                    key0=level2.attributes.values()[0].name.strip()
                    value0=level2.attributes.values()[0].value.strip()
                    print "key0 is ", key0
                    print "name is ", value0
                    if key0 == "type" :
                        actions[i].type=value0
                        for level3 in level2.childNodes :
                            if level3.toxml().strip('\r\n') <> "" :
                                print "level3 is:", level3.toxml()
                                print "lelve3 tagname", level3.tagName
                                print "level3 content",level3.childNodes[0].data
                                actions[i].attr[level3.tagName]=level3.childNodes[0].data
                        print key0," is ", value0
    return actions

#main procedure starts
filename ="default.txt"
remote="127.0.0.1"
listen=""
port=2123
times=1         
action_step={}  
get_argv(sys.argv[1:])
print "filename is ",filename,";remote is ",remote,";port is ",port
print "listen is ",listen, " times is ",times         
action_step=parse_xml(filename)
print action_step[1].action
if action_step[1].action =='send' :
    print "the first action is send, work as client mode"
    working_mode='client'
else :
    print "the first action is not send, work as server mode"
    working_mode='server'
    #create primary server socket
    server_primary_sock = socket.socket()
    server_primary_sock.bind((listen,port))
    

flags='32'
msg_type='10'
h_teid='00000000'
seq=1
n_pdu='02'
next_ext_head='00'
imsi='0000000000000004' 
recovery='00'
#my_ip=socks.getsockname()[0]
my_ip='192.168.6.161'
#Send PDP
packet=packet_set.gtp_packet(flags,msg_type,h_teid,seq,n_pdu,next_ext_head,imsi,recovery,my_ip)


times=int(times)
i=1
input_list=[]
output_list=[]
exec_list=[]
dict={}
action_obj={}
seq=1
while i <= times or input_list <> []:
    if working_mode== 'client' :
            #only client mode need cares times
            if i<=times:
                #obj_sock=packet_set.socks()
                thread = socket_thread.socket_thread(i,remote,port)
                sock_handle=thread.connect()
        	print "sock_handle is ",sock_handle
                action_obj[sock_handle]=[thread,1,packet]
                input_list.append(sock_handle)
                
                #obj_sock.socket[sock_handle]=thread
                #step=obj_sock.cur_step
        	cur_step=1
        	while action_step[cur_step].action=='send' :
        	    for key in action_step[cur_step].attr :
                        print "key:",key," value:",action_step[cur_step].attr[key]
                        setattr(packet, key, action_step[cur_step].attr[key])
                    print "packet.imsi is",packet.imsi
                    
                    packet.seq=seq
                    seq+=1
                    send_content=''
                    if action_step[cur_step].type=='create_pdp_req' :
                        send_content=packet.create_pdp_req()
                    elif action_step[cur_step].type=='update_pdp_req':
                        send_content=packet.update_pdp_req()
                    elif action_step[cur_step].type=='pdp_echo_req' :
                        send_content=packet.pdp_echo_req()
                    send_content=send_content.rstrip('\r\n')
                    action_obj[sock_handle][0].send(send_content)
                    action_obj[sock_handle][1]+=1
        	    print action_obj[sock_handle][1]
        	    cur_step+=1
                i+=1
    else :
             #server mode needs checking if there is new incoming connection. if there is then put new connection socket into input_list
             try :
                 server_sock, addr = server_primary_sock.accept()
                 input_list.append(server_sock)
             except socket.error, msg:
                 print "server socket error! %s" % msg
                 break
    
    input_ready,output_ready,exec_ready=select.select(input_list,output_list,exec_list,0.02)
    try:
        for s in input_ready:
            data=action_obj[s][0].recv().encode("hex")
            print "receive date:", data
            cur_step=action_obj[s][1]
            receive_good=0
            if action_step[cur_step].action=='recv':
                print "good! expect to receive, received"
                if data[2:4]=="11" and action_step[cur_step].type=='create_pdp_resp' :
                    print "received create_pdp_resp"
                    receive_good=1
                elif data[2:4]=="02" and action_step[cur_step].type=='pdp_echo_resp' :
                    print "received pdp_echo_resp"
                    receive_good=1
                else :
                    print "bad, received type is not expected!"
                    print "expect: ",action_step[cur_step].type,"; received: ",data[2:4]
            else :
                print "bad, expect action is ", action_step[cur_step].action, "but received data. Ignore it"
            if receive_good==1 :
                    increase_step=check_recv(action_step[cur_step],data)
                    action_obj[s][1]+=increase_step
		    if action_obj[s][1] in action_step:
			    while action_step[action_obj[s][1]].action=='send' :
				    print action_obj[s][0]
				    print action_obj[s][1]
				    print action_obj[s][2]
				    print action_step[6]
		                    increase_step=handle_action(seq,action_obj[s][0],action_obj[s][2],action_step[action_obj[s][1]])
                		    seq+=1
		                    action_obj[s][1]+=increase_step

                
    except socket.error, e:
        print "socket error:",id

 
